package com.xiaotu.spider.maoyan.pageprocessor;

import com.xiaotu.common.exception.SpiderException;
import com.xiaotu.common.exception.SpiderExceptionCode;
import com.xiaotu.common.model.StarAwardModel;
import com.xiaotu.common.util.*;
import com.xiaotu.spider.AUrlPageProcessor;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.selector.Html;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @类名 MaoYanStarAwardsPageProcessor
 * @日期 2017年7月31日
 * @作者 高海军
 * @功能 猫眼艺人获奖记录爬取
 */
@Component("MaoYanStarAwardsPageProcessor")
public class MaoYanStarAwardsPageProcessor extends AUrlPageProcessor
{
    //    public static final String LIST_URL = "https://piaofang.maoyan.com/celebrity-board?" +
    //            "uuid=82E21330AF9CA553292ECA5EB39A47B57D118231FD20E28CA8E6E5087265AE6A&" +
    //            "msid=AB63D462-2ED7-41BE-8740-A972B561CE0C%s&" +
    //            "utm_term=4.5&utm_source=AppStore&" +
    //            "utm_content=82E21330AF9CA553292ECA5EB39A47B57D118231FD20E28CA8E6E5087265AE6A&" +
    //            "version_name=4.5&utm_medium=iphone&" +
    //            "deviceId=82E21330AF9CA553292ECA5EB39A47B57D118231FD20E28CA8E6E5087265AE6A&" +
    //            "lat=39.973373&utm_campaign=AmovieproBmovieProH0&" +
    //            "pushToken=dpshd775d504b1ae86e582d4bb26a2639fe8itpu&regionid=&cLevel1Id=29&" +
    //            "f=ios&cityId=0&lng=116.407179&ci=0";

    //    private static final String DATE_FMT = "yyyy-MM-dd-HH-mmsss";

    private static final Logger LOGGER = LoggerFactory.getLogger(MaoYanStarAwardsPageProcessor
            .class);

    public static final String[] OCCP_IDS = new String[]{"29",/*演员*/"36",/*导演*/"55",
            /*编剧*/"47"/*制片*/};

    public static final String PAGE_URL = "https://piaofang.maoyan.com/celebrity-board/query" +
            "?page=%s&cLevel1Id=%s&cLevel2Id=-1&cId=-1&work-type=-1&work-style=-1&verified=-1" +
            "&gender=-1";

    public static final String AWARD_URL =
            "https://piaofang.maoyan.com/celebrity/achievement?id=%s";

    private String[] occpIdxes = null;

    private int startPageNo = 1;

    private String urlFile = null;

    private String failFile = null;

    @Override
    public void initRunParams(Map<String, Object> map)
    {
        if (map.containsKey("idx"))
        {
            String idxes = map.get("idx").toString();
            occpIdxes = StringUtils.isEmpty(idxes) ? null : idxes.split(SepratorUtil.SEP_COMMA_EN);
        }

        if (map.containsKey("page"))
        {
            String page = map.get("page").toString();
            startPageNo = RegexUtils.regexMatch(RegexUtils.REGEX_INTEGER, page) ? Integer
                    .parseInt(page) : startPageNo;
        }

        if (map.containsKey("urlFile"))
            this.urlFile = map.get("urlFile").toString();
        if (map.containsKey("failFile"))
            this.failFile = map.get("failFile").toString();
    }

    @SuppressWarnings("unchecked")
    @Override
    public void process(Page page)
    {
        switch (this.getPageDataType(page))
        {
            case Constants.PageDataType.SEARCH_LIST:
                this.listProcess(page);
                break;
            case Constants.PageDataType.STAR_RECORD:
                this.awardProcess(page);
                break;
            default:
                this.pageProcess(page);
                break;
        }
    }

    private void pageProcess(Page page)
    {
        if (this.validateFail(page, "分页"))
            return;
        String json = page.getRawText();
        if (StringUtils.isEmpty(json))
            throw new SpiderException(SpiderExceptionCode.DataInvalideException);
        Map<String, Object> jsonMap = GsonUtils.fromJson(json, Map.class);
        if (jsonMap == null || jsonMap.isEmpty() || jsonMap.get("data") == null)
            throw new SpiderException(SpiderExceptionCode.DataInvalideException);
        List<String> linkList = new Html(jsonMap.get("data").toString()).xpath("//a").all();
        this.addStarLink(page, linkList);

        if (true != (Boolean) jsonMap.get("hasMore"))
            return;
        String pageNo = this.getUrlNumParam(page, "\\?page=");
        String lelId = this.getUrlNumParam(page, "cLevel1Id=");
        PageUtils.addTargetRequest(page, String.format(PAGE_URL, Integer.valueOf(pageNo) + 1,
                lelId), page.getRequest().getExtras());
    }

    private boolean validateFail(Page page, String name)
    {
        if (page.getRawText() != null && page.getRawText().contains("请输入以下验证码恢复访问"))
        {
            if (StringUtils.isNotEmpty(failFile))
                FileUtil.writeFile(failFile, String.format("%s,%s", name, page.getUrl().toString
                        ()) + SepratorUtil.LINE_SEPRATOR);
            return true;
        }
        return false;
    }

    private void awardProcess(Page page)
    {
        String starName = page.getRequest().getExtra("name").toString();
        if (this.validateFail(page, starName))
        {
            LOGGER.warn("[{}] {} invalided fail[{}]", this.getSpiderType(), starName, page.getUrl()
                    .toString());
            return;
        }
        List<String> divList = page.getHtml().xpath("//div[@class='cele-achievement']/div").all();
        if (divList == null || divList.isEmpty())
        {
            LOGGER.warn("[{}] {} no awards[{}]", this.getSpiderType(), starName, page.getUrl()
                    .toString());
            return;
        }

        List<StarAwardModel> awardList = new ArrayList<>();
        StringBuffer timeBuffer = new StringBuffer();
        divList.forEach(divStr ->
        {
            List<String> entryList = new Html(divStr).xpath("//div[@class='entry']").all();
            if (entryList == null || entryList.size() < 2)
                return;
            String awardType = new Html(entryList.get(0)).
                    xpath("//div[@class='content']/p/text()").get();
            if (StringUtils.isEmpty(awardType))
                throw new SpiderException(SpiderExceptionCode.DataInvalideException);

            entryList.stream().skip(1).forEach(entryStr ->
            {
                Html html = new Html(entryStr);
                String awardTime = StringUtils.trim(html.xpath("//div[@class='title']/span/text()" +
                        "").get());
                awardTime = this.setTimeBuffer(timeBuffer, awardTime);

                String awardStr = StringUtils.trim(html.xpath("//div[@class='pull-left']/div/text" +
                        "()").get());
                if (StringUtils.isEmpty(awardStr))
                    throw new SpiderException(SpiderExceptionCode.DataInvalideException);
                String[] awardArr = awardStr.split(" ");
                if (awardArr.length < 2)
                    throw new SpiderException(SpiderExceptionCode.DataInvalideException);
                String awardWork = html.xpath("//div[@class='pull-left']/a/@data-name").get();
                String awardRole = html.xpath("//div[@class='pull-left']/a//span/text()").get();
                String awardMode = StringUtils.trim(html.xpath
                        ("//div[@class='pull-right']/div/text()").get());

                awardList.add(new StarAwardModel(Constants.SiteName.MAOYAN, starName, awardType,
                        awardArr[0], awardArr[1], awardWork, awardRole, awardTime, awardMode));
            });

            timeBuffer.delete(0, timeBuffer.length());
        });

        if (awardList.isEmpty())
            throw new SpiderException(SpiderExceptionCode.DataInvalideException);

        page.putField(StarAwardModel.class.getName(), awardList);
    }

    private String setTimeBuffer(StringBuffer buffer, String time)
    {
        if (StringUtils.isEmpty(time))
            return buffer.toString();
        if (buffer.length() > 0)
            buffer.delete(0, buffer.length());
        buffer.append(time);
        return buffer.toString();
    }

    private String getUrlNumParam(Page page, String regex)
    {
        String value = RegexUtils.regexSearch(regex + RegexUtils.REGEX_INTEGER, page.getUrl()
                .toString());
        value = RegexUtils.regexSearch("=" + RegexUtils.REGEX_INTEGER, value);
        value = RegexUtils.regexSearch(RegexUtils.REGEX_INTEGER, value);
        if (StringUtils.isEmpty(value))
            throw new SpiderException(SpiderExceptionCode.DataInvalideException, page.getUrl()
                    .toString());
        return value;
    }

    private void addStarLink(Page page, List<String> linkList)
    {
        if (linkList == null || linkList.isEmpty())
            throw new SpiderException(SpiderExceptionCode.DataInvalideException);
        linkList.forEach(linkStr ->
        {
            Html html = new Html(linkStr);
            String id = html.xpath("//a/@href").get();
            id = RegexUtils.regexSearch(RegexUtils.REGEX_INTEGER, StringUtil.urlDecode(id));
            if (StringUtils.isEmpty(id))
                return;
            String name = html.xpath("//div[@class='title-row']/span[@class='name']/text()").get();
            if (StringUtils.isEmpty(name))
                throw new SpiderException(SpiderExceptionCode.DataInvalideException);
            PageUtils.addTargetRequest(page, String.format(AWARD_URL, id), PageUtils
                    .getNewExtraMapFromPage(page, new String[]{"name"}, new Object[]{name}));
        });
    }

    private void listProcess(Page page)
    {
        this.addStarLink(page, new Html(page.getRawText()).xpath("//div[@class='people-list']/a")
                .all());
        PageUtils.addTargetRequest(page, String.format(PAGE_URL, 2), page.getRequest().getExtras());
    }

    @Override
    protected String[] getStartRequestUrls()
    {
        if (StringUtils.isNotEmpty(this.urlFile))
            return null;
        if (occpIdxes == null)
            return Stream.of(OCCP_IDS).map(id -> String.format(PAGE_URL, startPageNo, id)).toArray
                    (String[]::new);
        return Stream.of(occpIdxes).map(idx -> String.format(PAGE_URL, startPageNo, OCCP_IDS[Integer
                .parseInt(idx)])).toArray(String[]::new);
        //        return new String[]{String.format(LIST_URL, DateUtils.fomartDateToString(new
        // Date(),DATE_FMT))};
    }

    @Override
    protected List<JSONObject> getStartRequestUrlsAndParams()
    {
        List<String> lineList = FileUtil.readFileByLine(this.urlFile);
        if (lineList == null || lineList.isEmpty())
            return null;
        return lineList.stream().map(line ->
        {
            String[] values = line.split(SepratorUtil.SEP_COMMA_EN);
            JSONObject obj = new JSONObject();
            obj.put("name", values[0]);
            obj.put(URL_KEY, values[1]);
            return obj;
        }).collect(Collectors.toList());
    }

    @Override
    protected String getSpiderType()
    {
        return "MaoYanStarAwards";
    }

    @Override
    public String getPageDataType(Page page)
    {
        if (page.getUrl().toString().contains("celebrity-board?uuid"))//列表页面
            return Constants.PageDataType.SEARCH_LIST;
        if (page.getUrl().toString().contains("achievement?id="))//获奖页面
            return Constants.PageDataType.STAR_RECORD;
        return Constants.PageDataType.URL;//json格式的列表数据
    }

}
